package cc.shacocloud.mirage.restful.http;

import cc.shacocloud.mirage.restful.HttpRequest;
import cc.shacocloud.mirage.restful.HttpResponse;
import cc.shacocloud.mirage.utils.MethodParameter;
import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Type;

/**
 * HttpMessageConverter 的一种通用化，它可以将HTTP请求转换为指定泛型类型的目标对象，并将指定泛型类型的源对象转换为HTTP响应。
 */
public interface GenericHttpMessageConverter<T> extends HttpMessageConverter<T> {
    
    /**
     * 指示此转换器是否可以读取给定的类型。
     * 这个方法应该执行与{@link HttpMessageConverter#canRead(MethodParameter, Class, MediaType)}相同的检查，另外还有一些与泛型类型相关的检查。
     *
     * @param parameter    {@link MethodParameter}
     * @param type         用于测试可读性的(可能是泛型的)类型
     * @param contextClass 目标类型的上下文类，例如目标类型出现在方法签名中的类(可以是{@code null})
     * @param mediaType    要读取的媒体类型，如果没有指定，可以是{@code null}。通常是{@code Content-Type}头的值。
     * @return {@code true}如果可读;{@code false}
     */
    boolean canRead(MethodParameter parameter, Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType);
    
    /**
     * 从给定输入消息中读取给定类型的对象，并返回该对象。
     *
     * @param parameter    {@link MethodParameter }
     * @param type         用于测试可读性的(可能是泛型的)类型
     * @param contextClass 目标类型的上下文类，例如目标类型出现在方法签名中的类(可以是{@code null})
     * @param request      当前请求对象
     * @return 转换对象
     */
    Future<T> read(MethodParameter parameter, Type type, @Nullable Class<?> contextClass, HttpRequest request);
    
    /**
     * 指示给定的类是否可以由此转换器编写。
     * <p>
     * 此方法应该执行与 {@link HttpMessageConverter#canWrite(Class, MediaType)}相同的检查，另外还有与泛型类型相关的检查。
     *
     * @param type      测试可写性的(可能是通用的)类型(如果没有指定，可以是{@code null})
     * @param clazz     用于测试可写性的源对象类
     * @param mediaType 要写入的媒体类型(如果没有指定，可以是{@code null});通常是{@code Accept}头的值。
     * @return {@code true}如果可写;{@code false}
     */
    boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType);
    
    /**
     * 将给定的对象写入给定的输出消息。
     *
     * @param t           要写入输出消息的对象。该对象的类型之前必须被传递给该接口的{@link #canWrite canWrite}方法，
     *                    该方法必须返回{@code true}。
     * @param type        要写入的(可能是泛型的)对象类型。该类型之前必须已被传递给该接口的{@link #canWrite canWrite}方法，
     *                    该方法必须返回{@code true}。如果没有指定，可以是{@code null}。
     * @param contentType 写作时要使用的内容类型。
     *                    可能是{@code null} 表示必须使用转换器的默认内容类型。
     *                    如果不是{@code null}，则该媒体类型必须之前已被传递给该接口的
     *                    {@link #canWrite canWrite}方法，该方法必须返回* {@code true}。
     * @param response    响应体
     * @return {@link Future} 解析后的结果
     */
    Future<Buffer> write(T t, @Nullable Type type, @Nullable MediaType contentType, HttpResponse response);
    
}
